//#include <GL/gl.h>
//#include <GL/glu.h>
#include "Color.h"
#include <iostream>
#include "math.h"
#include <string.h>

#define window_width  800
#define window_height 600

SDL_Surface *screen;

SDL_Surface *avenue;
SDL_Surface *avenueV;
SDL_Surface *street;
SDL_Surface *streetV;
SDL_Surface *highway;
SDL_Surface *highwayV;

SDL_Surface *street23;

SDL_Surface *crossroads;

int xpos=0,ypos=0;

int makeTransparent(SDL_Surface* surface, Color c){
	  return SDL_SetColorKey(surface, SDL_SRCCOLORKEY, SDL_MapRGB(surface->format, c.getR(), c.getG(), c.getR()));
}

SDL_Surface * loadBMP(char* fileName){
	SDL_Surface* bmp = NULL;
	bmp = SDL_LoadBMP(fileName);

	if (bmp == NULL){
		std::string s("..\\");	
		s.append(fileName);
		bmp = SDL_LoadBMP(s.c_str());
	}
	return bmp;
}


int initImages(){
	avenue = loadBMP("avenue.bmp");
	avenueV = loadBMP("avenueV.bmp");
	street = loadBMP("street.bmp");
	streetV = loadBMP("streetV.bmp");
	highway = loadBMP("highway.bmp");
	highwayV = loadBMP("highwayV.bmp");

	crossroads = loadBMP("crossroads.bmp");
	street23 = loadBMP("street233.bmp");

	Color c = c.white;
	makeTransparent(avenue, c);
	makeTransparent(avenueV, c);
	makeTransparent(street, c);
	makeTransparent(streetV, c);
	makeTransparent(street23, c);
	makeTransparent(highway, c);
	makeTransparent(crossroads, c);

	return 0;
}

void drawIMG(SDL_Surface *img, int x, int y, SDL_Surface *background){
  SDL_Rect dest;
  dest.x = x;
  dest.y = y;
//  SDL_SetColorKey(img, SDL_SRCCOLORKEY, SDL_MapRGB(img->format, 255, 255, 255));
  SDL_BlitSurface(img, NULL, background, &dest);
}

void drawIMG(SDL_Surface *src, int xSrc, int ySrc, int wSrc, int hSrc, int xDest, int yDest, SDL_Surface *dest){
  SDL_Rect rectDest;
  rectDest.x = xDest;
  rectDest.y = yDest;

  SDL_Rect rectSrc;
  rectSrc.x = xSrc;
  rectSrc.y = ySrc;
  rectSrc.w = wSrc;
  rectSrc.h = hSrc;
//  SDL_SetColorKey(src, SDL_SRCCOLORKEY, SDL_MapRGB(src->format, 255, 255, 255));

  SDL_BlitSurface(src, &rectSrc, dest, &rectDest);
}

void drawPixel(SDL_Surface *screen, int x, int y, Uint8 R, Uint8 G, Uint8 B){
  Uint32 color = SDL_MapRGB(screen->format, R, G, B);
  switch (screen->format->BytesPerPixel)
  {
    case 1: // 8-bpp
      {
        Uint8 *bufp;
        bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;
        *bufp = color;
      }
      break;
    case 2: // 15-bpp - 16-bpp
      {
        Uint16 *bufp;
        bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x;
        *bufp = color;
      }
      break;
    case 3: // 24-bpp
      {
        Uint8 *bufp;
        bufp = (Uint8 *)screen->pixels + y*screen->pitch + x * 3;
        if(SDL_BYTEORDER == SDL_LIL_ENDIAN)
        {
          bufp[0] = color;
          bufp[1] = color >> 8;
          bufp[2] = color >> 16;
        } else {
          bufp[2] = color;
          bufp[1] = color >> 8;
          bufp[0] = color >> 16;
        }
      }
      break;
    case 4: // 32-bpp
      {
        Uint32 *bufp;
		bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;
		*bufp = color;
      }
      break;
  }
}

void drawPixel(SDL_Surface *screen, int x, int y, Color c){
	drawPixel(screen, x, y, c.getR(), c.getG(), c.getB());
}

void lock(SDL_Surface *screen){
  if ( SDL_MUSTLOCK(screen) )
  {
    if ( SDL_LockSurface(screen) < 0 )
    {
      return;
    }
  }
}

void unlock(SDL_Surface *screen){
  if ( SDL_MUSTLOCK(screen) )
  {
    SDL_UnlockSurface(screen);
  }
}

void drawSurface(SDL_Surface *screen, Color c){
	lock(screen);
	for(int x=0;x<window_width;x++)
	{
	  for(int y=0;y<window_height;y++)
	  {
	    drawPixel(screen, x,y,c);
	  }
	}
	unlock(screen);
	SDL_Flip(screen);
}

void drawHLine(SDL_Surface *screen, int leftmost, int rightmost, int y, Color c){
	int begin = leftmost;
	int end = rightmost;
	if (rightmost < leftmost){
		begin = rightmost;
		end = leftmost;
	}

	for (int x = begin; x < end; x++){
		drawPixel(screen, x, y, c);
	}
	SDL_Flip(screen);
}

void drawSpriteV(SDL_Surface* sprite, int x, int y, int w, int h, SDL_Surface* backgroud){
	// TODO Verificar esto...
	int spriteW = sprite->w;
	int spriteH = sprite->h;
	int mod = h % spriteH;
	int q = h / spriteH;
	int i;

	for (i = 0; i < q; i++){
		drawIMG(sprite, 0, 0, spriteW, spriteH, x, y + (i * spriteH), backgroud);
	}

	if (mod > 0){
		drawIMG(sprite, 0, 0, spriteW, mod, x, y + (i * spriteH), backgroud);
	}
	SDL_Flip(backgroud);
}

void drawSpriteH(SDL_Surface* sprite, int x, int y, int w, int h, SDL_Surface* backgroud){
	// TODO Verificar esto...
	int spriteW = sprite->w;
	int spriteH = sprite->h;
	int mod = w % spriteW;
	int q = w / spriteW;
	int i;

	for (i = 0; i < q; i++){
		drawIMG(sprite, 0, 0, spriteW, spriteH, x + (i*spriteW), y, backgroud);
	}

	if (mod > 0){
		drawIMG(sprite, 0, 0, mod, spriteH, x + (i*spriteW), y, backgroud);
	}
	SDL_Flip(backgroud);
}

void findXY(int x1, int y1, int x2, int y2, int* xo, int* xf, int* yo, int* yf){
	if (x1 < x2){
		*xo = x1;
		*xf = x2;
	} else {
		*xo = x2;
		*xf = x1;
	}

	if (y1 < y2){
		*yo = y1;
		*yf = y2;
	} else {
		*yo = y2;
		*yf = y1;
	}
}

float calcAngle(int x1, int y1, int x2, int y2){
	float angle = 0.0;

	float opposite = abs(y2 - y1);
	float adjacent = abs(x2 - x1);

	angle = atan(opposite / adjacent);
	return angle;
}

float calcLength(int x1, int y1, int x2, int y2){
	float length = 0.0;

	float opposite = abs(x2 - x1);
	float adjacent = abs(y2 - y1);

	length = sqrt((opposite * opposite) + (adjacent * adjacent));
	return length;
}

float calcLength(SDL_Surface* surface, float angle){
	// TODO Implementar esto usando angle
	return (calcLength(0, 0, surface->w, surface->h));
}

SDL_Surface* getSurfaceFor(float angle, SDL_Surface* sprite){
	return street23;
}

float calcXYRatio(SDL_Surface* surface){
	int w = surface->w;
	int h = surface->h;
	float ratio = w/h;
	return ratio;
}

int calcWidth(float length, float xyRatio){
	return length * xyRatio;
}

void calcNextXY(int i, int* x, int*y, int spriteW, int spriteH){
	int dx = *x;
	int dy = *y;

	if (i > 0){
		dx = dx + spriteW;
		dy = dy + spriteH;
		dx = dx - (0.10 * dx);
		dy = dy - (0.10 * dy);
	}
	*x = dx;
	*y = dy;
}

void drawSprite(SDL_Surface* sprite, int x1, int y1, int x2, int y2, SDL_Surface* backgroud){
	int xo, xf, yo, yf;

	findXY(x1, y1, x2, y2, &xo, &xf, &yo, &yf);

	float angle = calcAngle(xo, yo, xf, yf);
	float length = calcLength(xo, yo, xf, yf);
	SDL_Surface* rotatedSurface = getSurfaceFor(angle, sprite);

	float xyRatio = calcXYRatio(rotatedSurface);
	float spriteLength = calcLength(rotatedSurface, angle);
	spriteLength = spriteLength * 0.6561;

	int spriteW = rotatedSurface->w;
	int spriteH = rotatedSurface->h;

	int q = length / spriteLength;
	float mod = length - (spriteLength * q);

	int i;

	int x = xo;
	int y = yo;

	for (i = 0; i < q; i++){
		calcNextXY(i, &x, &y, spriteW, spriteH);
		std::cout << "X: " << x << std::endl;
		std::cout << "Y: " << y << std::endl;
		drawIMG(rotatedSurface, 0, 0, spriteW, spriteH, x, y, backgroud);
	}

	if (mod > 0){
		calcNextXY(i, &x, &y, spriteW, spriteH);
		drawIMG(rotatedSurface, 0, 0, mod * cos(angle), mod * sin(angle), x, y, backgroud);
	}

	SDL_Flip(backgroud);
}

int main(int argc, char *argv[]) {
	// Initialize SDL with best video mode
	if (SDL_Init(SDL_INIT_VIDEO) < 0){
		std::cout << "Could not initialize video\n";
	} else {
		const SDL_VideoInfo* info = SDL_GetVideoInfo();
		int vidFlags = SDL_GL_DOUBLEBUFFER;
		if (info->hw_available == 0) {
			vidFlags |= SDL_SWSURFACE;
		} else {
			vidFlags |= SDL_HWSURFACE;
		}
		int bpp = info->vfmt->BitsPerPixel;
		screen = SDL_SetVideoMode(window_width, window_height, bpp, vidFlags);
		//SDL_SetAlpha(screen, SDL_SRCALPHA, 127);
		initImages();

		int done=0;
		SDL_Event event;
		bool repaint = true;

		while(done == 0)
		{
		  Color c = c.white;
		  if (repaint){

			  drawSurface(screen, c);

			  drawSpriteH(highway, 0, 10, 400, 20, screen);
			  drawSpriteH(street, 20, 50, 100, 20, screen);
			  drawSpriteH(street, 140, 50, 100, 20, screen);
			  drawSpriteH(street, 140, 170, 100, 20, screen);
			  drawSpriteH(street, 20, 170, 100, 20, screen);

			  drawSpriteV(avenueV, 120, 30, 20, 20, screen);
			  drawSpriteV(avenueV, 120, 70, 20, 100, screen);
			  drawSpriteV(streetV, 220, 70, 20, 100, screen);
			  drawSpriteV(streetV, 0, 70, 20, 100, screen);
			  drawSpriteV(streetV, 0, 30, 20, 20, screen);
			  drawSpriteV(streetV, 220, 30, 20, 20, screen);

			  drawSprite(street, 125, 60, 240, 100, screen);

			  drawSpriteH(crossroads, 0, 50, 20, 20, screen);
			  drawSpriteH(crossroads, 0, 170, 20, 20, screen);
			  drawSpriteH(crossroads, 120, 50, 20, 20, screen);
			  drawSpriteH(crossroads, 220, 50, 20, 20, screen);
			  drawSpriteH(crossroads, 220, 100, 20, 20, screen);
			  drawSpriteH(crossroads, 220, 170, 20, 20, screen);
			  drawSpriteH(crossroads, 120, 170, 20, 20, screen);

		  }
		  Color w = w.black;
		  //drawHLine(screen, 10, 50, 50, w);
		  //drawIMG(image, xpos, ypos, 40, 40, xpos, ypos, screen);
		  //drawSpriteV(image, xpos, ypos, 40, 100, screen);


		  while ( SDL_PollEvent(&event) ){
			  if ( event.type == SDL_QUIT ){
				  done = 1;
			  } else {
				  repaint = false;
			  }
		  }
		}
	}
	return 0;
}
